home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #12 / Amiga Plus CD - 2002 - No. 12.iso / Tools / Development / qstat25b / config.c < prev    next >
C/C++ Source or Header  |  2002-11-18  |  22KB  |  958 lines

  1. /*
  2.  * qstat 2.5a
  3.  * by Steve Jankowski
  4.  * steve@qstat.org
  5.  * http://www.qstat.org
  6.  *
  7.  * Copyright 1996,1997,1998,1999 by Steve Jankowski
  8.  *
  9.  * Licensed under the Artistic License, see LICENSE.txt for license terms
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <ctype.h>
  16.  
  17. #include "config.h"
  18.  
  19. #ifdef __hpux
  20. #define STATIC static
  21. #else
  22. #define STATIC
  23. #endif
  24.  
  25. #ifdef _WIN32
  26. #define strcasecmp      stricmp
  27. #endif
  28.  
  29.  
  30. #ifdef _WIN32
  31. #define HOME_CONFIG_FILE "qstat.cfg"
  32. #else
  33. #define HOME_CONFIG_FILE ".qstatrc"
  34. #endif
  35.  
  36.  
  37. static server_type ** config_types;
  38. static int n_config_types;
  39. static int max_config_types;
  40. static int next_gametype_id= LAST_BUILTIN_SERVER+1;
  41.  
  42. static int load_config_file( char *filename);
  43. static int try_load_config_file( char *filename, int show_error);
  44. static int pf_top_level( char *text, void *context);
  45. static int pf_gametype_new( char *text, void *context);
  46. static int pf_gametype_modify( char *text, void *context);
  47.  
  48. static int set_game_type_value( server_type *gametype, int key, char *value);
  49. static int modify_game_type_value( server_type *gametype, int key, char *value);
  50. static int set_packet_value( server_type *gametype, char *value,
  51.     char *packet_name, char **packet, int *len);
  52.  
  53. static char *first_token( char *text);
  54. static char *next_token();
  55. static char *next_token_dup();
  56. static char *next_value();
  57. static char * parse_value( char *source, int len);
  58. static unsigned int parse_hex( char *hex, int len, int *error);
  59. static unsigned int parse_oct( char *oct, int len, int *error);
  60. static char *force_lower_case( char *string);
  61. static char *force_upper_case( char *string);
  62. static char *get_token();
  63. static void * memdup( void *mem, unsigned int len);
  64.  
  65. static int (*parse_func)( char *, void *);
  66. static void *parse_context;
  67. static int line;
  68. static char *current_file_name;
  69.  
  70. static char *parse_text;
  71. static char *parse_end;
  72. static char *lex;
  73. static char *token_end;
  74. static char token_buf[1024];
  75. static int value_len;
  76.  
  77. static int debug= 0;
  78.  
  79. #define REPORT_ERROR(a)        print_location(); fprintf a; fprintf(stderr, "\n")
  80.  
  81. #define CK_MASTER_PROTOCOL    1
  82. #define CK_MASTER_QUERY        2
  83. #define CK_MASTER_PACKET    3
  84. #define CK_NAME            4
  85. #define CK_DEFAULT_PORT        5
  86. #define CK_GAME_RULE        6
  87. #define CK_TEMPLATE_VAR        7
  88. #define CK_MASTER_TYPE        8
  89. #define CK_STATUS_PACKET    9
  90. #define CK_STATUS2_PACKET    10
  91. #define CK_PLAYER_PACKET    11
  92. #define CK_RULE_PACKET        12
  93. #define CK_PORT_OFFSET        13
  94.  
  95.  
  96. typedef struct _config_key {
  97.     int key;
  98.     char *key_name;
  99. } ConfigKey;
  100.  
  101. static ConfigKey new_keys[] = {
  102. { CK_MASTER_PROTOCOL, "master protocol" },
  103. { CK_MASTER_QUERY, "master query" },
  104. { CK_MASTER_PACKET, "master packet" },
  105. { CK_NAME, "name" },
  106. { CK_DEFAULT_PORT, "default port" },
  107. { CK_GAME_RULE, "game rule" },
  108. { CK_TEMPLATE_VAR, "template var" },
  109. { CK_MASTER_TYPE, "master for gametype" },
  110. { CK_STATUS_PACKET, "status packet" },
  111. { CK_STATUS2_PACKET, "status2 packet" },
  112. { CK_PLAYER_PACKET, "player packet" },
  113. { CK_RULE_PACKET, "rule packet" },
  114. { CK_PORT_OFFSET, "status port offset" },
  115. { 0, NULL },
  116. };
  117.  
  118. static ConfigKey modify_keys[] = {
  119. { CK_MASTER_PROTOCOL, "master protocol" },
  120. { CK_MASTER_QUERY, "master query" },
  121. { CK_MASTER_PACKET, "master packet" },
  122. { 0, NULL },
  123. };
  124.  
  125. static int get_config_key( char *first_token, ConfigKey *keys);
  126. static void add_config_type( server_type *gametype);
  127. static server_type * get_config_type( char *game_type);
  128. static void copy_server_type( server_type *dest, server_type *source);
  129. static server_type * get_server_type( char *game_type);
  130.  
  131. typedef struct _gametype_context {
  132.     char *type;
  133.     char *extend_type;
  134.     server_type *gametype;
  135. } GameTypeContext;
  136.  
  137.  
  138. static void
  139. print_location()
  140. {
  141.     fprintf( stderr, "%s line %d: ", current_file_name, line);
  142. }
  143.  
  144. int
  145. qsc_load_default_config_files()
  146. {
  147.     int rc= 0;
  148.     char *filename= NULL, *var;
  149.     char path[1024];
  150.  
  151.     var= getenv( "QSTAT_CONFIG");
  152.     if ( var != NULL && var[0] != '\0')  {
  153.     rc= try_load_config_file( var, 1);
  154.     if ( rc == 0 || rc == -1)
  155.         return rc;
  156.     }
  157.  
  158.     var= getenv( "HOME");
  159.     if ( var != NULL && var[0] != '\0')  {
  160.     sprintf( path, "%s/%s", var, HOME_CONFIG_FILE);
  161.     rc= try_load_config_file( path, 0);
  162.     if ( rc == 0 || rc == -1)
  163.         return rc;
  164.     }
  165.  
  166. #ifdef sysconfdir
  167.     strcpy( path, sysconfdir "/qstat.cfg");
  168.     filename= path;
  169. #elif defined(_WIN32)
  170.     if ( filename == NULL && _pgmptr && strchr( _pgmptr, '\\'))  {
  171.         char *slash= strrchr( _pgmptr, '\\');
  172.         strncpy( path, _pgmptr, slash - _pgmptr);
  173.         path[slash - _pgmptr]= '\0';
  174.         strcat( path, "\\qstat.cfg");
  175.         filename= path;
  176.     }
  177. #endif
  178.  
  179.     if ( filename != NULL)  {
  180.     rc= try_load_config_file( filename, 0);
  181.     if ( rc == 0 || rc == -1)
  182.         return rc;
  183.     }
  184.     return rc;
  185. /*
  186.     if ( rc == -2 && show_error)  {
  187.     perror( filename);
  188.     fprintf( stderr, "Error: Could not open config file \"%s\"\n",
  189.         filename);
  190.     }
  191.     else if ( rc == -1 && show_error)
  192.     fprintf( stderr, "Error: Error loading $QSTAT_CONFIG file\n");
  193.     return rc;
  194. */
  195.  
  196. #ifdef foo
  197.     filename= getenv( "HOME");
  198.     if ( filename != NULL && filename[0] != '\0')  {
  199.     char path[1024];
  200.     sprintf( path, "%s/%s", filename, HOME_CONFIG_FILE);
  201.     }
  202. /* 1. $QSTAT_CONFIG
  203.    2. UNIX: $HOME/.qstatrc         WIN: $HOME/qstat.cfg
  204.    3. UNIX: sysconfdir/qstat.cfg   WIN: qstat.exe-dir/qstat.cfg
  205. */
  206.  
  207.     rc= load_config_file( "qstat.cfg");
  208.     if ( rc == -1)
  209.     fprintf( stderr, "Warning: Error loading default qstat.cfg\n");
  210.     return 0;
  211. #endif
  212. }
  213.  
  214. int
  215. qsc_load_config_file( char *filename)
  216. {
  217.     int rc= load_config_file( filename);
  218.     if ( rc == -2)  {
  219.     perror( filename);
  220.     fprintf( stderr, "Could not open config file \"%s\"\n",
  221.         filename);
  222.     return -1;
  223.     }
  224.     return rc;
  225. }
  226.  
  227. server_type **
  228. qsc_get_config_server_types( int *n_config_types_ref)
  229. {
  230.     if ( n_config_types_ref)
  231.     *n_config_types_ref= n_config_types;
  232.     return config_types;
  233. }
  234.  
  235. STATIC int
  236. try_load_config_file( char *filename, int show_error)
  237. {
  238.     int rc= load_config_file( filename);
  239.     if ( rc == -2 && show_error)  {
  240.     perror( filename);
  241.     fprintf( stderr, "Error: Could not open config file \"%s\"\n",
  242.         filename);
  243.     }
  244.     else if ( rc == -1)
  245.     fprintf( stderr, "Error: Could not load config file \"%s\"\n",
  246.         filename);
  247.     return rc;
  248. }
  249.  
  250. STATIC int
  251. load_config_file( char *filename)
  252. {
  253.     FILE *file;
  254.     int rc;
  255.  
  256.     file= fopen( filename, "r");
  257.     if ( file == NULL)
  258.     return -2;
  259.  
  260.     current_file_name= filename;
  261.     rc= parse_config_file( file);
  262.     fclose(file);
  263.     return rc;
  264. }
  265.  
  266. int
  267. parse_config_file( FILE *file)
  268. {
  269.     char buf[4096];
  270.     int rc;
  271.  
  272.     line= 0;
  273.     parse_func= pf_top_level;
  274.  
  275.     while ( fgets( buf, sizeof(buf), file) != NULL)  {
  276.     int len= strlen(buf);
  277.     while ( len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
  278.        len--;
  279.     buf[len]= '\0';
  280.     line++;
  281.     rc= parse_func( buf, parse_context);
  282.     if ( rc != 0)
  283.         return rc;
  284.     }
  285.     return 0;
  286. }
  287.  
  288.  
  289. /* Top level
  290.  *   Keywords: gametype
  291.  */
  292. STATIC int
  293. pf_top_level( char *text, void *_context)
  294. {
  295.     GameTypeContext *context;
  296.     server_type *extend;
  297.     char *token, *game_type, *extend_type;
  298.     token= first_token( text);
  299.     if ( token == NULL)
  300.     return 0;
  301.  
  302.     if ( strcmp( token, "gametype") != 0)  {
  303.     REPORT_ERROR(( stderr, "Unknown config command \"%s\"", token));
  304.     return -1;
  305.     }
  306.  
  307.     game_type= next_token_dup();
  308.     if ( game_type == NULL)  {
  309.     REPORT_ERROR(( stderr, "Missing game type"));
  310.     return -1;
  311.     }
  312.  
  313.     force_lower_case( game_type);
  314.  
  315.     token= next_token();
  316.     if ( token == NULL)  {
  317.     REPORT_ERROR(( stderr, "Expecting \"new\" or \"modify\""));
  318.     return -1;
  319.     }
  320.  
  321.     if ( strcmp( token, "new") == 0)  {
  322.     parse_func= pf_gametype_new;
  323.     }
  324.     else if ( strcmp( token, "modify") == 0)  {
  325.     parse_func= pf_gametype_modify;
  326.     }
  327.     else  {
  328.     REPORT_ERROR(( stderr, "Expecting \"new\" or \"modify\""));
  329.     return -1;
  330.     }
  331.  
  332.     context= (GameTypeContext*) malloc( sizeof(GameTypeContext));
  333.     context->type= game_type;
  334.     context->extend_type= NULL;
  335.     context->gametype= NULL;
  336.  
  337.     token= next_token();
  338.  
  339.     if ( parse_func == pf_gametype_modify)  {
  340.     if ( token != NULL)  {
  341.         REPORT_ERROR(( stderr, "Extra text after gametype modify"));
  342.         return -1;
  343.     }
  344.     context->gametype= get_server_type( game_type);
  345.     if ( context->gametype == NULL)  {
  346.         REPORT_ERROR(( stderr, "Unknown game type \"%s\"", game_type));
  347.         free(context);
  348.         return -1;
  349.     }
  350.     parse_context= context;
  351.     return 0;
  352.     }
  353.  
  354.     if ( token == NULL || strcmp( token, "extend") != 0)  {
  355.     REPORT_ERROR(( stderr, "Expecting \"extend\""));
  356.     return -1;
  357.     }
  358.  
  359.     extend_type= next_token();
  360.  
  361.     if ( extend_type == NULL)  {
  362.     REPORT_ERROR(( stderr, "Missing extend game type"));
  363.     return -1;
  364.     }
  365.  
  366.     force_lower_case( extend_type);
  367.  
  368.     if ( strcasecmp( extend_type, game_type) == 0)  {
  369.     REPORT_ERROR(( stderr, "Identical game type and extend type"));
  370.     return -1;
  371.     }
  372.  
  373.     context->extend_type= extend_type;
  374.     extend= get_server_type( extend_type);
  375.     if ( extend == NULL)  {
  376.     REPORT_ERROR(( stderr, "Unknown extend game type \"%s\"", extend_type));
  377.     return -1;
  378.     }
  379.  
  380.     /* Over-write a previous gametype new */
  381.     context->gametype= get_config_type( game_type);
  382.     if ( context->gametype == NULL)
  383.     context->gametype= (server_type*) malloc( sizeof(server_type));
  384.     copy_server_type( context->gametype, extend);
  385.  
  386.     /* Set flag for new type-id if not re-defining previous config type */
  387.     if ( get_config_type( game_type) == NULL)
  388.     context->gametype->id= 0;
  389.  
  390.     context->gametype->type_string= game_type;
  391.     context->gametype->type_prefix= strdup(game_type);
  392.     force_upper_case( context->gametype->type_prefix);
  393.     context->gametype->type_option= (char*)malloc( strlen(game_type)+2);
  394.     context->gametype->type_option[0]= '-';
  395.     strcpy( &context->gametype->type_option[1], game_type);
  396.  
  397.     parse_context= context;
  398.  
  399.     return 0;
  400. }
  401.  
  402. STATIC int
  403. pf_gametype_modify( char *text, void *_context)
  404. {
  405.     GameTypeContext *context= (GameTypeContext*) _context;
  406.     char *token;
  407.     int key;
  408.  
  409.     token= first_token( text);
  410.     if ( token == NULL)
  411.     return 0;
  412.  
  413.     if ( strcmp( token, "end") == 0)  {
  414.     parse_func= pf_top_level;
  415.     parse_context= NULL;
  416.     return 0;
  417.     }
  418.  
  419.     key= get_config_key( token, modify_keys);
  420.  
  421.     token= next_token();
  422.  
  423.     if ( strcmp( token, "=") != 0)  {
  424.     REPORT_ERROR(( stderr, "Expecting \"=\", found \"%s\"", token));
  425.     return -1;
  426.     }
  427.  
  428.     token= next_value();
  429.     if ( token == NULL)  {
  430.     REPORT_ERROR(( stderr, "Missing value after \"=\""));
  431.     return -1;
  432.     }
  433.  
  434.     if ( debug)
  435.     printf( "%d %s = <%s>\n", key, modify_keys[key-1].key_name,
  436.         token?token:"");
  437.  
  438.     return modify_game_type_value( context->gametype, key, token);
  439. }
  440.  
  441. STATIC int
  442. pf_gametype_new( char *text, void *_context)
  443. {
  444.     GameTypeContext *context= (GameTypeContext*) _context;
  445.     char *token;
  446.     int key;
  447.  
  448.     token= first_token( text);
  449.     if ( token == NULL)
  450.     return 0;
  451.  
  452.     if ( strcmp( token, "end") == 0)  {
  453.     add_config_type( context->gametype);
  454.     parse_func= pf_top_level;
  455.     parse_context= NULL;
  456.     return 0;
  457.     }
  458.  
  459.     key= get_config_key( token, new_keys);
  460.  
  461.     if ( key <= 0)
  462.     return key;
  463.  
  464.     token= next_token();
  465.     if ( strcmp( token, "=") != 0)  {
  466.     REPORT_ERROR(( stderr, "Expecting \"=\", found \"%s\"", token));
  467.     return -1;
  468.     }
  469.  
  470.     token= next_value();
  471.     if ( token == NULL && (key != CK_MASTER_PROTOCOL && key != CK_MASTER_QUERY))  {
  472.     REPORT_ERROR(( stderr, "Missing value after \"=\""));
  473.     return -1;
  474.     }
  475.  
  476.     if ( debug)
  477.     printf("%d %s = <%s>\n", key, new_keys[key-1].key_name, token?token:"");
  478.  
  479.     return set_game_type_value( context->gametype, key, token);
  480. }
  481.  
  482. STATIC int
  483. get_config_key( char *first_token, ConfigKey *keys)
  484. {
  485.     char key_name[1024], *token;
  486.     int key= 0;
  487.  
  488.     strcpy( key_name, first_token);
  489.     do  {
  490.     int k;
  491.     for ( k= 0; keys[k].key_name; k++)  {
  492.         if ( strcmp( keys[k].key_name, key_name) == 0)  {
  493.         key= keys[k].key;
  494.         break;
  495.         }
  496.     }
  497.     if ( key)
  498.         break;
  499.     token= next_token();
  500.     if ( token == NULL || strcmp( token, "=") == 0)
  501.         break;
  502.     if ( strlen(key_name) + strlen(token) > sizeof(key_name)-2)  {
  503.         REPORT_ERROR(( stderr, "Key name too long"));
  504.         return -1;
  505.     }
  506.     strcat( key_name, " ");
  507.     strcat( key_name, token);
  508.     } while ( 1);
  509.  
  510.     if ( key == 0)  {
  511.     REPORT_ERROR(( stderr, "Unknown config key \"%s\"", key_name));
  512.     return -1;
  513.     }
  514.  
  515.     return key;
  516. }
  517.  
  518. STATIC int
  519. set_game_type_value( server_type *gametype, int key, char *value)
  520. {
  521.     switch ( key)  {
  522.     case CK_NAME:
  523.     gametype->game_name= strdup(value);
  524.     break;
  525.     case CK_DEFAULT_PORT: {
  526.     unsigned short port;
  527.     if ( sscanf( value, "%hu", &port) != 1)  {
  528.         REPORT_ERROR(( stderr, "Syntax error on port.  Should be a number between 1 and 65535."));
  529.         return -1;
  530.     }
  531.     gametype->default_port= port;
  532.     break;
  533.     }
  534.     case CK_GAME_RULE:
  535.     gametype->game_rule= strdup(value);
  536.     break;
  537.     case CK_TEMPLATE_VAR:
  538.     gametype->template_var= strdup(value);
  539.     force_upper_case( gametype->template_var);
  540.     break;
  541.     case CK_MASTER_PROTOCOL:
  542.     if ( ! gametype->master)  {
  543.         REPORT_ERROR((stderr, "Cannot set master protocol on non-master game type\n"));
  544.         return -1;
  545.     }
  546.     if ( value)
  547.         gametype->master_protocol= strdup(value);
  548.     else
  549.         gametype->master_protocol= NULL;
  550.     break;
  551.     case CK_MASTER_QUERY:
  552.     if ( ! gametype->master)  {
  553.         REPORT_ERROR((stderr, "Cannot set master query on non-master game type\n"));
  554.         return -1;
  555.     }
  556.     if ( value)
  557.         gametype->master_query= strdup(value);
  558.     else
  559.         gametype->master_query= NULL;
  560.     break;
  561.     case CK_MASTER_TYPE:
  562.     {
  563.     server_type *type;
  564.     if ( ! gametype->master)  {
  565.         REPORT_ERROR((stderr, "Cannot set master type on non-master game type\n"));
  566.         return -1;
  567.     }
  568.     force_lower_case( value);
  569.     type= get_server_type( value);
  570.     if ( type == NULL)  {
  571.         REPORT_ERROR((stderr, "Unknown server type \"%s\"\n", value));
  572.         return -1;
  573.     }
  574.     gametype->master= type->id;
  575.     }
  576.     break;
  577.     case CK_MASTER_PACKET:
  578.     if ( ! gametype->master)  {
  579.         REPORT_ERROR((stderr, "Cannot set master packet on non-master game type"));
  580.         return -1;
  581.     }
  582.     if ( value == NULL || value[0] == '\0')  {
  583.         REPORT_ERROR((stderr, "Empty master packet"));
  584.         return -1;
  585.     }
  586.     gametype->master_packet= memdup( value, value_len);
  587.     gametype->master_len= value_len;
  588.     break;
  589.     case CK_STATUS_PACKET:
  590.     return set_packet_value( gametype, value, "status",
  591.         &gametype->status_packet, &gametype->status_len);
  592.     case CK_STATUS2_PACKET:
  593.     return set_packet_value( gametype, value, "status2",
  594.         &gametype->rule_packet, &gametype->rule_len);
  595.     case CK_PLAYER_PACKET:
  596.     return set_packet_value( gametype, value, "player",
  597.         &gametype->player_packet, &gametype->player_len);
  598.     case CK_RULE_PACKET:
  599.     return set_packet_value( gametype, value, "rule",
  600.         &gametype->rule_packet, &gametype->rule_len);
  601.     case CK_PORT_OFFSET:  {
  602.     short port;
  603.     if ( sscanf( value, "%hd", &port) != 1)  {
  604.         REPORT_ERROR(( stderr, "Syntax error on port.  Should be a number between 32767 and -32768."));
  605.         return -1;
  606.     }
  607.     gametype->port_offset= port;
  608.     break;
  609.     }
  610.     }
  611.  
  612.     return 0;
  613. }
  614.  
  615. STATIC int
  616. set_packet_value( server_type *gametype, char *value, char *packet_name,
  617.     char **packet, int *len)
  618. {
  619.     if ( gametype->master)  {
  620.     REPORT_ERROR((stderr, "Cannot set info packet on master game type"));
  621.     return -1;
  622.     }
  623.     if ( value == NULL || value[0] == '\0')  {
  624.         REPORT_ERROR((stderr, "Empty %s packet", packet_name));
  625.         return -1;
  626.     }
  627.     if ( *packet == NULL)  {
  628.         REPORT_ERROR((stderr, "Cannot set %s packet; extend game type does not define a %s packet", packet_name, packet_name));
  629.         return -1;
  630.     }
  631.     *packet= memdup( value, value_len);
  632.     *len= value_len;
  633.     return 0;
  634. }
  635.  
  636. STATIC int
  637. modify_game_type_value( server_type *gametype, int key, char *value)
  638. {
  639.     switch ( key)  {
  640.     case CK_MASTER_PROTOCOL:
  641.     if ( ! gametype->master)  {
  642.         REPORT_ERROR((stderr, "Cannot set master protocol on non-master game type"));
  643.         return -1;
  644.     }
  645.     if ( value)
  646.         gametype->master_protocol= strdup(value);
  647.     else
  648.         gametype->master_protocol= NULL;
  649.     break;
  650.     case CK_MASTER_QUERY:
  651.     if ( ! gametype->master)  {
  652.         REPORT_ERROR((stderr, "Cannot set master query on non-master game type"));
  653.         return -1;
  654.     }
  655.     if ( value)
  656.         gametype->master_query= strdup(value);
  657.     else
  658.         gametype->master_query= NULL;
  659.     break;
  660.     case CK_MASTER_PACKET:
  661.     if ( ! gametype->master)  {
  662.         REPORT_ERROR((stderr, "Cannot set master packet on non-master game type"));
  663.         return -1;
  664.     }
  665.     if ( value == NULL || value[0] == '\0')  {
  666.         REPORT_ERROR((stderr, "Empty master packet"));
  667.         return -1;
  668.     }
  669.     gametype->master_packet= memdup( value, value_len);
  670.     break;
  671.     }
  672.     return 0;
  673. }
  674.  
  675. STATIC server_type *
  676. get_server_type( char *game_type)
  677. {
  678.     server_type *result;
  679.     result= find_server_type_string( game_type);
  680.     if ( result != NULL)
  681.     return result;
  682.  
  683.     return get_config_type( game_type);
  684. }
  685.  
  686. STATIC void
  687. add_config_type( server_type *gametype)
  688. {
  689.     if ( gametype->id == 0)  {
  690.     if ( next_gametype_id >= MASTER_SERVER)  {
  691.         REPORT_ERROR(( stderr, "Exceeded game type limit, ignoring \"%s\"",
  692.         gametype->type_string));
  693.         return;
  694.     }
  695.     gametype->id= next_gametype_id;
  696.     if ( gametype->master)
  697.         gametype->id |= MASTER_SERVER;
  698.     next_gametype_id++;
  699.     }
  700.  
  701.     if ( max_config_types == 0)  {
  702.     max_config_types= 4;
  703.     config_types= (server_type**) malloc(sizeof(server_type*) * (max_config_types + 1));
  704.     }
  705.     else if ( n_config_types >= max_config_types)  {
  706.     max_config_types*= 2;
  707.     config_types= (server_type**) realloc( config_types,
  708.         sizeof(server_type*) * (max_config_types + 1));
  709.     }
  710.     config_types[ n_config_types]= gametype;
  711.     n_config_types++;
  712. }
  713.  
  714. STATIC server_type *
  715. get_config_type( char *game_type)
  716. {
  717.     server_type **search= config_types;
  718.     int i;
  719.     for ( i= 0; i < n_config_types; i++)
  720.     if ( strcmp( config_types[i]->type_string, game_type) == 0)
  721.         return config_types[i];
  722.  
  723.     return NULL;
  724. }
  725.  
  726. STATIC void
  727. copy_server_type( server_type *dest, server_type *source)
  728. {
  729.     *dest= *source;
  730. }
  731.  
  732. STATIC void *
  733. memdup( void *mem, unsigned int len)
  734. {
  735.     void *result= malloc( len);
  736.     memcpy( result, mem, len);
  737.     return result;
  738. }
  739.  
  740. /* Parsing primitives
  741.  */
  742.  
  743. STATIC char *
  744. first_token( char *text)
  745. {
  746.     parse_text= text;
  747.     parse_end= parse_text + strlen( parse_text);
  748.     lex= text;
  749.     token_end= text;
  750.  
  751.     if ( *lex == '#')
  752.     return NULL;
  753.  
  754.     return get_token();
  755. }
  756.  
  757. STATIC char *
  758. next_token()
  759. {
  760.     lex= token_end;
  761.     return get_token();
  762. }
  763.  
  764. STATIC char *
  765. next_token_dup()
  766. {
  767.     return strdup( next_token());
  768. }
  769.  
  770. STATIC char *
  771. get_token()
  772. {
  773.     char *token= &token_buf[0];
  774.     while ( isspace(*token_end))
  775.     token_end++;
  776.  
  777.     if ( token_end == parse_end)
  778.     return NULL;
  779.  
  780.     while ( (isalnum(*token_end) || *token_end == '.' || *token_end == '_' || *token_end == '-')
  781.         && token < &token_buf[0] + sizeof(token_buf))
  782.     *token++= *token_end++;
  783.  
  784.     if ( token == &token_buf[0])
  785.     *token++= *token_end++;
  786.     *token= '\0';
  787.     return &token_buf[0];
  788. }
  789.  
  790. extern void print_packet( struct qserver *server, char *buf, int buflen);
  791.  
  792. STATIC char *
  793. next_value()
  794. {
  795.     char *token= &token_buf[0];
  796.     while ( isspace(*token_end))
  797.     token_end++;
  798.  
  799.     if ( token_end == parse_end)
  800.     return NULL;
  801.  
  802.     while ( token_end < parse_end && token < &token_buf[0] + sizeof(token_buf))
  803.     *token++= *token_end++;
  804.  
  805.     *token--= '\0';
  806.  
  807.     if ( strchr( token_buf, '\\'))
  808.     return parse_value(token_buf, (token - token_buf)+1);
  809.  
  810.     while ( isspace(*token))
  811.     *token--= '\0';
  812.  
  813.     value_len= token - token_buf + 1;
  814.  
  815.     return &token_buf[0];
  816. }
  817.  
  818. STATIC char *
  819. parse_value( char *source, int len)
  820. {
  821.     char *value, *v, *end;
  822.     int error= 0, rc;
  823.     unsigned int n;
  824.  
  825.     value= (char*)malloc( len + 1);
  826.     v= value;
  827.  
  828. /*
  829. printf( "parse_value <%.*s>\n", len, source);
  830. */
  831.  
  832.     for ( ; len; len--, source++)  {
  833.     if ( *source != '\\')  {
  834.         *v++= *source;
  835.         if ( *source != ' ')
  836.         end= v;
  837.         continue;
  838.     }
  839.     source++; len--;
  840.     if ( len == 0)
  841.         break;
  842.     if ( *source == '\\')
  843.         *v++= *source;
  844.     else if ( *source == 'n')
  845.         *v++= '\n';
  846.     else if ( *source == 'r')
  847.         *v++= '\r';
  848.     else if ( *source == ' ')
  849.         *v++= ' ';
  850.     else if ( *source == 'x')  {
  851.         source++; len--;
  852.         if ( len < 2)
  853.         break;
  854.         *v++= parse_hex(source, 2, &error);
  855.         if ( error)
  856.         break;
  857.         source++; len--;
  858.     }
  859.     else if ( isdigit( *source))  {
  860.         if ( len < 3)
  861.         break;
  862.         *v++= parse_oct(source, 3, &error);
  863.         if ( error)
  864.         break;
  865.         source++; len--;
  866.         source++; len--;
  867.     }
  868.     else  {
  869.         error= 1;
  870.         REPORT_ERROR(( stderr, "Invalid character escape \"%.*s\"", 2,
  871.         source-1));
  872.         break;
  873.     }
  874.     end= v;
  875.     }
  876.  
  877.     if ( error)  {
  878.     free(value);
  879.     return NULL;
  880.     }
  881.  
  882.     value_len= end - value;
  883.     memcpy( token_buf, value, value_len);
  884.     token_buf[value_len]= '\0';
  885.  
  886. /*
  887. print_packet(NULL, token_buf, value_len);
  888. */
  889.  
  890.     free(value);
  891.     return &token_buf[0];
  892. }
  893.  
  894. STATIC unsigned int
  895. parse_hex( char *hex, int len, int *error)
  896. {
  897.     char *save_hex= hex;
  898.     int save_len= len;
  899.     unsigned int result= 0;
  900.     *error= 0;
  901.     for ( ; len; len--, hex++)  {
  902.     result <<= 4;
  903.     if ( ! isxdigit( *hex))  {
  904.         *error= 1;
  905.         REPORT_ERROR(( stderr, "Invalid hex \"%.*s\"", save_len+2,
  906.         save_hex-2));
  907.         return 0;
  908.     }
  909.     if ( *hex >= '0' && *hex <= '9')
  910.         result|= *hex - '0';
  911.     else if ( *hex >= 'A' && *hex <= 'F')
  912.         result|= ((*hex - 'A') + 10);
  913.     else if ( *hex >= 'a' && *hex <= 'f')
  914.         result|= ((*hex - 'a') + 10);
  915.     }
  916.     return result;
  917. }
  918.  
  919. STATIC unsigned int
  920. parse_oct( char *oct, int len, int *error)
  921. {
  922.     char *save_oct= oct;
  923.     int save_len= len;
  924.     unsigned int result= 0;
  925.     *error= 0;
  926.     for ( ; len; len--, oct++)  {
  927.     result <<= 3;
  928.     if ( *oct >= '0' && *oct <= '7')
  929.         result|= *oct - '0';
  930.     else  {
  931.         *error= 1;
  932.         REPORT_ERROR(( stderr, "Invalid octal \"%.*s\"", save_len+1,
  933.         save_oct-1));
  934.         return 0;
  935.     }
  936.     }
  937.     return result;
  938. }
  939.  
  940. STATIC char *
  941. force_lower_case( char *string)
  942. {
  943.     char *s= string;
  944.     for ( ; *s; s++)
  945.     *s= tolower(*s);
  946.     return string;
  947. }
  948.  
  949. STATIC char *
  950. force_upper_case( char *string)
  951. {
  952.     char *s= string;
  953.     for ( ; *s; s++)
  954.     *s= toupper(*s);
  955.     return string;
  956. }
  957.  
  958.